#region

using System.IO;
using HtmlAgilityPack;
using System.Collections.Generic;
using System.Text;
using System;
using System.Xml;

#endregion

namespace SalarSoft.ASProxy.BuiltIn
{
    public class HtmlToText
    {
        List<Entity> _Entities = new List<Entity>();
        int NfId = 0;
        #region Public Methods

        public string Translate(string html)
        {
            HtmlDocument doc = new HtmlDocument();
            doc.LoadHtml(html);
            StringWriter sw = new StringWriter();
            string _Text = TranslateTo(doc.DocumentNode);
            TranslateLanguage(doc, _Text);
            doc.Save(sw);
            sw.Flush();
            return sw.ToString();
        }

        public string Convert(string path)
        {
            HtmlDocument doc = new HtmlDocument();
            doc.Load(path);

            StringWriter sw = new StringWriter();
            ConvertTo(doc.DocumentNode, sw);
            sw.Flush();
            return sw.ToString();
        }

        public string ConvertHtml(string html)
        {
            HtmlDocument doc = new HtmlDocument();
            doc.LoadHtml(html);

            StringWriter sw = new StringWriter();
            ConvertTo(doc.DocumentNode, sw);
            sw.Flush();
            return sw.ToString();
        }

        public void ConvertTo(HtmlNode node, TextWriter outText)
        {
            string html;
            switch (node.NodeType)
            {
                case HtmlNodeType.Comment:
                    // don't output comments
                    break;

                case HtmlNodeType.Document:
                    ConvertContentTo(node, outText);
                    break;

                case HtmlNodeType.Text:
                    // script and style must not be output
                    string parentName = node.ParentNode.Name;
                    if ((parentName == "script") || (parentName == "style"))
                        break;

                    // get text
                    html = ((HtmlTextNode)node).Text;

                    // is it in fact a special closing node output as text?
                    if (HtmlNode.IsOverlappedClosingElement(html))
                        break;

                    // check the text is meaningful and not a bunch of whitespaces
                    if (html.Trim().Length > 0)
                    {
                        outText.Write(HtmlEntity.DeEntitize(html));
                    }
                    break;

                case HtmlNodeType.Element:
                    switch (node.Name)
                    {
                        case "p":
                            // treat paragraphs as crlf
                            outText.Write("\r\n");
                            break;
                    }

                    if (node.HasChildNodes)
                    {
                        ConvertContentTo(node, outText);
                    }
                    break;
            }
        }

        public string TranslateTo(HtmlNode node)
        {
            string _Text = "";
            string html;
            switch (node.NodeType)
            {
                case HtmlNodeType.Comment:
                    // don't output comments
                    break;

                case HtmlNodeType.Document:
                    _Text = TranslateContentTo(node);
                    break;

                case HtmlNodeType.Text:
                    // script and style must not be output
                    string parentName = node.ParentNode.Name;
                    if ((parentName == "script") || (parentName == "style"))
                        break;

                    // get text
                    html = ((HtmlTextNode)node).Text;

                    // is it in fact a special closing node output as text?
                    if (HtmlNode.IsOverlappedClosingElement(html))
                        break;

                    // check the text is meaningful and not a bunch of whitespaces
                    if (html.Trim().Length > 0)
                    {
                        _Text = HtmlEntity.DeEntitize(html);
                    }
                    break;

                case HtmlNodeType.Element:
                    switch (node.Name)
                    {
                        case "p":
                            break;
                    }

                    if (node.HasChildNodes)
                    {
                        _Text = TranslateContentTo(node);
                    }
                    break;
            }
            return _Text.Trim();
        }

        private void TranslateLanguage(HtmlDocument doc, string Xml)
        {
            try
            {
                XmlDocument _TempXml = new XmlDocument();
                Xml = Xml.Replace("&", "&amp;");
                _TempXml.LoadXml(Xml);
                ProcessXml(_TempXml.DocumentElement);
                string Text = string.Empty;
                foreach (Entity e in _Entities.FindAll(o => !String.IsNullOrEmpty(o.Text)))
                {
                    Text += string.Format("{0}--@--{1}--NT--", e.Id, e.Text);
                }
                //Text = Text.TrimEnd('\n');
                TranslationService.BNLPService _Serv = new TranslationService.BNLPService();
                Text = _Serv.TranslateSite(Text);
                string[] _RArray = Text.Split(new string[] { "--NT--" }, StringSplitOptions.None);

                foreach (string _s in _RArray)
                {
                    string[] _Temp = _s.Split(new string[] { "--@--" }, StringSplitOptions.None);
                    if (_Temp.Length > 1)
                    {
                        Entity _Entity = _Entities.Find(o => o.Id.Equals(_Temp[0]));
                        //doc.GetElementbyId(_Temp[0]).InnerHtml = _Temp[1];
                        string _TempText = String.Format("<Entity id=\"{0}\">{1}</Entity>", _Temp[0], _Temp[1]); ;
                        //_TempXml = new XmlDocument();
                        _TempXml.LoadXml(_TempText);
                        foreach (XmlNode _Child in _TempXml.DocumentElement.ChildNodes)
                        {
                            if (_Child.Attributes != null && _Child.Attributes["id"] != null)
                            {
                                Entity _EntityChild = _Entities.Find(o => o.Id.Equals(_Child.Attributes["id"].Value));
                                if (_EntityChild != null)
                                {
                                    string _Idc = ((HtmlNode)_Entity.Node).Id;
                                    if (_Idc.StartsWith("NfId_"))
                                    {
                                        ((HtmlNode)_Entity.Node).SetAttributeValue("id", "");
                                    }
                                    ((HtmlNode)_EntityChild.Node).InnerHtml = _Child.InnerText;
                                    _Temp[1] = _Temp[1].Replace(_Child.OuterXml, ((HtmlNode)_EntityChild.Node).OuterHtml);
                                }
                            }
                        }
                        string _Id = ((HtmlNode)_Entity.Node).Id;
                        if (_Id.StartsWith("NfId_"))
                        {
                            ((HtmlNode)_Entity.Node).SetAttributeValue("id", "");
                        }
                        ((HtmlNode)_Entity.Node).InnerHtml = _Temp[1];
                    }
                }
            }
            catch (Exception ex)
            {
            }
        }

        private void ProcessXml(XmlNode _XmlParent)
        {
            foreach (XmlNode _Child in _XmlParent.ChildNodes)
            {
                ProcessXml(_Child);
                if (_Child.Attributes != null && _Child.Attributes["id"] != null)
                {
                    Entity _Entity = _Entities.Find(o => o.Id.Equals(_Child.Attributes["id"].Value));
                    if (_Child.InnerXml.StartsWith("<"))
                    {
                        if (_Child.ChildNodes == null || _Child.ChildNodes.Count == 1)
                        {
                            _Entities.Remove(_Entity);
                        }
                    }
                    else
                    {
                        if (!String.IsNullOrEmpty(_Child.InnerXml))
                        {
                            _Entity.Text = _Child.InnerXml;
                            foreach (XmlNode _N in _Child.ChildNodes)
                            {
                                if (_N.Attributes != null && _N.Attributes["id"] != null)
                                {
                                    Entity _Entitychild = _Entities.Find(o => o.Id.Equals(_N.Attributes["id"].Value));
                                    if (_Entitychild != null)
                                    {
                                        _Entitychild.Text = String.Empty;
                                    }
                                }
                            }
                        }
                        else
                        {
                            _Entities.Remove(_Entity);
                        }
                    }
                }
            }
        }

        private string TranslateLanguage(string Text)
        {
            //TranslationService.TestService _Serv = new TranslationService.TestService();
            //Text = _Serv.Translate(Text);
            return Text;
        }

        #endregion

        #region Private Methods

        private void ConvertContentTo(HtmlNode node, TextWriter outText)
        {
            foreach (HtmlNode subnode in node.ChildNodes)
            {
                ConvertTo(subnode, outText);
            }
        }

        private string TranslateContentTo(HtmlNode node)
        {
            string _Text = String.Empty;

            foreach (HtmlNode subnode in node.ChildNodes)
            {
                _Text += TranslateTo(subnode);
            }
            if (!String.IsNullOrEmpty(_Text) && node.ParentNode != null)
            {
                Entity _Entity = new Entity();
                if (string.IsNullOrEmpty(node.Id))
                {
                    node.SetAttributeValue("id", "NfId_" + NfId.ToString());
                    NfId++;
                }
                _Entity.Id = node.Id;
                _Entity.Node = node;
                _Entities.Add(_Entity);

                _Text = String.Format("<Entity id=\"{0}\">{1}</Entity>", node.Id, _Text);
            }

            return _Text;
        }

        #endregion
    }

    public class Entity
    {
        public string Id { get; set; }
        public Object Node { get; set; }
        public string Text { get; set; }
    }
}